home *** CD-ROM | disk | FTP | other *** search
/ IRIX Installation Tools & Overlays 2001 November / SGI IRIX Installation Tools & Overlays 2001 November - Disc 1.iso / dist / roboinst.idb / usr / etc / roboinst_config.z / roboinst_config
Text File  |  2001-10-10  |  14KB  |  578 lines

  1. #! /usr/sbin/perl
  2. #Tag 0x00000f00
  3. #ident "$Revision $"
  4.  
  5. # Copyright 1997-1998, Silicon Graphics, Inc.
  6. # All Rights Reserved.
  7. #
  8. # This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  9. # the contents of this file may not be disclosed to third parties, copied or
  10. # duplicated in any form, in whole or in part, without the prior written
  11. # permission of Silicon Graphics, Inc.
  12. #
  13. # RESTRICTED RIGHTS LEGEND:
  14. # Use, duplication or disclosure by the Government is subject to restrictions
  15. # as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  16. # and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  17. # successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  18. # rights reserved under the Copyright Laws of the United States.
  19.  
  20. # roboinst_config
  21. #
  22. # verifies the format of the roboinst scripts and builds
  23. # a table of contents (list of scripts).
  24. # verifies the format of the mrconfig file.
  25.  
  26. # Initialization
  27.  
  28. $TMPDIR = $ENV{'TMPDIR'} || '/usr/tmp';
  29.  
  30. $ROOT = $ENV{'ROOT'};
  31.  
  32. @dirs = split(/\//,$0);
  33. $O = "$dirs[$#dirs]";
  34.  
  35. $Tempfile = "$TMPDIR/${O}.$$";
  36.  
  37. $RoboDir = "./";
  38.  
  39. $VERSION = "1";
  40. $GETHOSTBYNAME = "/usr/etc/gethostbyname";
  41.  
  42. $CFFilename = "mrconfig";
  43.  
  44. # mrconfig keywords
  45.  
  46. @cffilenames = (
  47.     "init", "fx", "mkfs", "preinst", "postinst"
  48. );
  49.  
  50. @cfkeywords = (
  51.     "version", "partition", "inst", "loghost", "disksetup", "onerror",
  52.     "nokernel", "if", "else", "elsif", "endif", "fi", "setenv",
  53.     @cffilenames
  54. );
  55.  
  56. # partition type keywords
  57.  
  58. @typekeywords = (
  59.     "root", "option", "standard",
  60.     "xfs", "xfs/blocksize", "efs", "swap",
  61.     "preserve", "protect"
  62. );
  63.  
  64. # size keywords
  65.  
  66. @sizekeywords = (
  67.     "existing", "standard", "all", "remainder"
  68. );
  69.  
  70. #
  71. # Parse Command Line Options
  72. #
  73.  
  74. $usage =
  75.     "usage: ${O} [ -nx ] [ -c configdir ] \n";
  76.  
  77. require 'getopts.pl';        # fancy option parsing
  78.  
  79. if (! &Getopts('c:dnxy')) {
  80.     die $usage;
  81. }
  82.  
  83. if ($opt_c) {
  84.     $RoboDir = $opt_c;
  85.     $RoboDir .= "/" if ($RoboDir !~ m|/$|);
  86. }
  87.  
  88. if (! -d $RoboDir) {
  89.     die "${RoboDir}: not a directory\n";
  90. }
  91.  
  92. print "${O}: indexing $RoboDir\n";
  93.  
  94. chdir($RoboDir) || die "${O}: unable to chdir to $RoboDir\n";
  95.  
  96. &mrcf_parse($CFFilename);
  97.  
  98. $IndexFile = ".index";
  99.  
  100. # miniroot libraries
  101.  
  102. @mr_solist =
  103.     (
  104.      "libc.so", "libC.so", "libCsup.so", "libc.so",
  105.      "libcrypt.so", "libcurses.so", "libdisk.so", "libgen.so",
  106.      "libinst.so", "libm.so", "libmalloc.so", "libw.so"
  107.      );
  108.  
  109. # check directory
  110.  
  111. &build_index();
  112.  
  113. exit(0);
  114.  
  115. #
  116. # ---- end of main processing ----
  117. #
  118.  
  119. # build_index - check the specified directory for /robo files
  120.  
  121. sub build_index {
  122.  
  123.     &open_index();
  124.  
  125.     open(FILES,"find . -follow -print |") ||
  126.     die "${O}: cannot find files\n";
  127.  
  128.     while (<FILES>) {
  129.     chop;            # strip eol
  130.     s|^\./||;        # strip ./
  131.     next if (m/^\.index$/ || m/^\.\.?$/);
  132.     if (m/\.BAK$/i || m/~$/) { # skip backup files
  133.         print "${O}: skipping backup file $_\n";
  134.         next;
  135.     }
  136.  
  137.     local($name) = $RoboDir . $_;
  138.     local($fname) = $_;
  139.  
  140.     print "Checking $fname\n" if ($opt_d);
  141.  
  142.     local($dev,$ino,$modeint,$nlink,$uid,$gid,$rdev,$size,
  143.           $atime,$mtime,$ctime,$blksize,$blocks) = stat($fname);
  144.  
  145.     local($mode) = sprintf("%o",$modeint & 0777);
  146.  
  147.     local($ftype) = `file $fname`;
  148.     if (-d $fname) {
  149.         print INDEX "$fname type=d mode=$mode\n";
  150.     } else {
  151.         local($executable) = 1;
  152.         local($sum) = `sum -r $fname | nawk '{print \$1}'`;
  153.         chop($sum);
  154.  
  155.         if ($ftype =~ m|(/bin/[ck]?sh)|) {
  156.         local($res) = `$1 -n $fname 2>&1`;
  157.         local(@lines) = split(/\n/,$res);
  158.         foreach $res (@lines) {
  159.             warn "${name}: $res\n";
  160.         }
  161.         } elsif ($ftype =~ m/:\s+(.*) script text/) {
  162.         local($intrp) = $1;
  163.         unless ($intrp =~ m,(root|custom)/.*perl,i) {
  164.             warn "${name}: ${intrp} script might not run in the miniroot\n";
  165.         }
  166.         } elsif ($ftype =~ m/:\s+(.*) executable/) {
  167.         local($exe) = $1;
  168.         if ($ftype !~ m/ELF N(ew )?32/) {
  169.             warn "${name}: $exe executable will not run in the miniroot,\n  must be ELF New 32 (N32) binary\n";
  170.         } else {
  171.             if ($ftype =~ m/not stripped/) {
  172.             warn "${name}: $exe executable is not stripped, see strip(1)\n";
  173.             }
  174.             unless (-e "$ROOT/usr/bin/elfdump") {
  175.             warn "${O}: unable to check library compatibility, elfdump(1) not installed\n";
  176.             } elsif (open(ELF,"elfdump -Dl $fname |")) {
  177.             while ($line = <ELF>) {
  178.                 if ($line =~ m/\s(lib\S+\.so)\S+\s/) {
  179.                 local($lib) = $1;
  180.                 local($found) = 0;
  181.                 foreach (@mr_solist) {
  182.                     $found = 1 if ($lib eq $_);
  183.                 }
  184.                 unless ($found) {
  185.                     warn "${name}: requires non-miniroot library \"$lib\"\n";
  186.                 }
  187.                 }
  188.             }
  189.             close(ELF);
  190.             }
  191.         }
  192.         } else {
  193.         $executable = 0;
  194.         }
  195.         if ($executable && ! -x _) {
  196.         warn "${name}: script should have execute permission\n";
  197.         }
  198.         if ($fname =~ m/$CFFilename\..*$/) {
  199.         warn "${name}: file may be overwritten by roboinst during install,\n  it is suggested that you rename the file\n";
  200.         }
  201.  
  202.         if ($opt_x) {
  203.         print INDEX "$fname type=f mode=$mode\n";
  204.         } else {
  205.         print INDEX "$fname type=f mode=$mode size=$size sum=$sum\n";
  206.         }
  207.     }
  208.     }
  209.  
  210.     close(FILES);
  211.  
  212.     &close_index();
  213. }
  214.  
  215. # open_index - open a new index file, prompt if overwrite
  216.  
  217. sub open_index {
  218.  
  219.     if (! $opt_n) {
  220.     if ((! $opt_y) && open(INDEX,"<$IndexFile")) {
  221.         close(INDEX);
  222.         if (-t) {
  223.         print "${O}: index file \"$IndexFile\" exists.  Overwrite? [yn] ";
  224.         $_ = <STDIN>;
  225.         } else {
  226.         $_ = "n";
  227.         }
  228.         if (! m/^\s*[yY]/) {
  229.         die "${O}: index file \"$IndexFile\" already exists.\n";
  230.         }
  231.     }
  232.     unlink $IndexFile;
  233.  
  234.     open(INDEX,">$IndexFile") ||
  235.         die "$RoboDir${IndexFile}: cannot create\n";
  236.     } else {
  237.     open(INDEX,"| cat") ||
  238.         die "${O}: cannot echo commands\n";
  239.     }
  240.  
  241.     print INDEX "# mrscript index\n";
  242.     print INDEX "# created by ${O}\n";
  243.     print INDEX "# version $VERSION\n";
  244.  
  245.     print "Creating index file \"$RoboDir$IndexFile\"\n" if ($opt_d);
  246. }
  247.  
  248. sub close_index {
  249.     close(INDEX);
  250. }
  251.  
  252. # mrcf_parse
  253. #
  254. # read and parse the given mrconfig file
  255. # display any errors
  256.  
  257. sub mrcf_parse {
  258.     local($cfname) = @_;
  259.  
  260.     unless (open(MRCF,"<$cfname")) {
  261.     print STDERR "${cfname}: unable to open mrconfig file\n";
  262.     return;
  263.     }
  264.  
  265.     print "Checking $cfname\n" if ($opt_d);
  266.  
  267.     undef %DiskSize;
  268.     undef %mrtemp;
  269.     undef %mrscripts;
  270.  
  271.     foreach $i (@cffilenames) {
  272.     $mrtemp{$i} = "${Tempfile}.$i";
  273.     local($fileid) = $i;
  274.     $fileid =~ tr/a-z/A-Z/;
  275.     eval "open($fileid,\">$mrtemp{$i}\");";
  276.     die "${O}: cannot open temporary file \"$mrtemp{$i}\"\n" if $@;
  277.     eval "print $fileid \"#! /bin/sh\n\";";
  278.     }
  279.  
  280.     while (<MRCF>) {
  281.     chop;            # strip newline
  282.     next unless ($_);    # skip blank lines
  283.     s/^\s*//;        # strip leading whitespace
  284.     next if (m/^\#/);    # skip comments
  285.  
  286.     local($found) = 0;
  287.     foreach $i (@cfkeywords) {
  288.         if (m/^$i>?\s*$/i || m/^$i>?\s?(.*)$/i) {
  289.         # strip extra whitespace
  290.         local($args) = $1;
  291.         $args =~ s/(\W)/\\$1/g;
  292.  
  293.         eval "&cfkey_$i(\"$args\")";
  294.         $found = 1;
  295.         last;
  296.         }
  297.     }
  298.     unless ($found) {
  299.         warn "${cfname}: unknown directive \"$_\"\n";
  300.     }
  301.     }
  302.  
  303.     close(MRCF);
  304.  
  305.     foreach $i (@cffilenames) {
  306.     local($fileid) = $i;
  307.     $fileid =~ tr/a-z/A-Z/;
  308.     eval "close($fileid);";
  309.     die "${O}: cannot close temporary file \"$mrtemp{$i}\"\n" if $@;
  310.  
  311.     print "Checking $i script $mrtemp{$i}\n" if $opt_d;
  312.     local($res) = `/bin/sh -n $mrtemp{$i} 2>&1`;
  313.     $res =~ s/^${Tempfile}\.//;
  314.     warn "mrconfig: $res" if ($res);
  315.     unlink $mrtemp{$i};
  316.     }
  317. }
  318.  
  319. sub cfkey_partition {
  320.     local($argstr) = @_;
  321.     local($disk);
  322.  
  323.     local($partition,$size,$type,$name,$options) = split(' ',$argstr,5);
  324.  
  325.     # verify partition
  326.  
  327.     if ($partition =~ m/(\S+):(\/\S+)/) { # network disk
  328.     local($server,$path) = ($1,$2);
  329.     `/usr/etc/ping -q -c 1 $server`;
  330.     unless ($?) {
  331.         warn "${server}: unable to contact remote host\n";
  332.     }
  333.     if ($path !~ m|^(/\w*)+$|) {
  334.         warn "${partition}: partition has questionable pathname\n";
  335.     }
  336.     unless ($type eq "nfs") {
  337.         warn "${partition}: remote disk must have type \"nfs\"\n";
  338.     }
  339.     $disk = $type;        # shouldn't be used, but better to have a value
  340.     } else {
  341.     unless ($partition =~ m/^(dks[0-9]+d[0-9]+)(vh|vol|s[0-9]+)$/ ||
  342.         $partition =~ m/^(systemdisk[0-9]*)(vh|vol|s[0-9]+|)$/) {
  343.     $disk = $1;
  344.         warn "${partition}: partition does not seem to specify a legal disk\n";
  345.     }
  346.     if ($type eq "nfs") {
  347.         warn "${partition}: local disk cannot have type \"nfs\"\n";
  348.     }
  349.     }
  350.  
  351.     # verify size
  352.  
  353.     $size =~ tr/A-Z/a-z/;    # lowercase
  354.  
  355.     local($sz_start,$sz_block) = ("0","0");
  356.     if ($size =~ m/:/) {
  357.     ($sz_start,$size) = split(':',$size,2);
  358.     }
  359.     if ($size =~ m|/|) {
  360.     ($size,$sz_block) = split('/',$size);
  361.     }
  362.  
  363.     if ($sz_start =~ m/^followspart([0-9]+)/) {
  364.     # processing unknown
  365.     } elsif ($sz_start !~ m/^[0-9]+$/) {
  366.     warn "${partition}: partition start address \"$sz_start\" is invalid\n";
  367.     }
  368.  
  369.     unless ($sz_block =~ m/^[0-9]+$/ &&    # numeric
  370.         ($sz_block % 512 == 0) && # multiple of 512
  371.         ($sz_block <= 65536)) { # maximum size
  372.     warn "${partition}: partition blocksize \"$sz_block\" is invalid\n";
  373.     }
  374.  
  375.     if ($size =~ m/^([0-9]+)(%?)$/) {
  376.     if ($2) {        # percentage
  377.         # NOTE: currently not supported...
  378.         local($total) = $DiskSize{$disk} + $1;
  379.         if ($total > 100) {
  380.         warn "${partition}: partition percentage totals more than 100%\n";
  381.         }
  382.         $DiskSize{$disk} = $total;
  383.     }
  384.  
  385.     } else {
  386.     # there is no way to do a more detailed check without parsing
  387.     # the "if" statements in mrconfig, as well as knowing the size
  388.     # of the target disk(s).
  389.     unless (grep(/^$size$/, @sizekeywords)) {
  390.         warn "${partition}: partition size \"$size\" is invalid\n";
  391.     }
  392.     }
  393.  
  394.     # check type
  395.  
  396.     if ($type =~ m|/|) {
  397.     ($type,$xfs_block) = split('/',$type);
  398.     } else {
  399.     $xfs_block = "4096";
  400.     }
  401.  
  402.     local($found) = 0;
  403.     foreach $i (@typekeywords) {
  404.     if ($type eq $i) {
  405.         $found = 1;
  406.         last;
  407.     }
  408.     }
  409.     if ($found) {
  410.     if ($type eq "swap") {
  411.         if ($name ne "swap" && $name ne "") {
  412.         warn "${partition}: swap partition does not have name \"swap\"\n";
  413.         }
  414.     } elsif ($type eq "xfs") {
  415.  
  416.         unless ($xfs_block =~ m/^[0-9]+$/ &&    # numeric
  417.             ($xfs_block % 512 == 0) && # multiple of 512
  418.             ($xfs_block <= 65536)) { # maximum size
  419.         warn "${partition}: partition blocksize \"$xfs_block\" is invalid\n";
  420.         }
  421.     } elsif ($type eq "protect") {
  422.         # do nothing
  423.     } elsif ($type eq "root" || $type eq "option" || $type eq "miniroot") {
  424.         warn "${partition}: $type partition must specify size \"standard\"\n"
  425.         unless ($size eq "standard");
  426.     } else {        # not swap
  427.         if ($name eq "nomount") {
  428.         print "${partition}: nomount\n" if ($opt_d);
  429.         } elsif ($name !~ m|^(/\w*)+$|) {
  430.         warn "${partition}: partition has questionable mount point \"$name\"\n";
  431.         }
  432.     }
  433.     } else {
  434.     warn "${partition}: partition has invalid type \"$type\"\n";
  435.     }
  436.  
  437. }
  438.  
  439. sub cfkey_version {
  440.     local($version) = @_;
  441.  
  442.     if (int($version) > int($VERSION)) {
  443.     warn "${cfname}: version $version not supported (newer than $VERSION)\n";
  444.     }
  445. }
  446.  
  447. sub cfkey_onerror {
  448.     local($action) = @_;
  449.  
  450.     if ($action ne "wait" && $action ne "ignore" && $action ne "abort") {
  451.     warn "${cfname}: onerror keyword requires one of the following arguments: wait, ignore, abort\n";
  452.     }
  453. }
  454.  
  455. sub cfkey_nokernel {
  456.     local($typestr) = @_;
  457.  
  458.     warn "${cfname}: nokernel takes no options ($typestr)\n" if ($typestr);
  459. }
  460.  
  461. sub cfkey_disksetup {        # if it's here, it's
  462.     local($typestr) = @_;
  463.  
  464.     warn "${cfname}: disksetup takes no options ($typestr)\n" if ($typestr);
  465. }
  466.  
  467. sub cfkey_setenv {
  468.     local ($var, $val) = @_;
  469.     if ($var eq "") {
  470.     warn "${cfname}: setenv keyword takes a variable name\n";
  471.     }
  472. }
  473.  
  474. sub cfkey_loghost {
  475.     local($server) = @_;
  476.  
  477.     print "Checking loghost $server\n" if ($opt_d);
  478.  
  479.     local($host);
  480.     chop($host = `hostname`);
  481.     local($thisipaddr) = &getipaddr($host);
  482.  
  483.     foreach $host (split(' ',$server)) {
  484.     local($ipaddr);
  485.     if ($host !~ m/^([0-9]{1,3}\.){3}[0-9]{1,3}$/) {
  486.         warn "${cfname}: loghost \"$host\" should be specified as IP address\n";
  487.     }
  488.  
  489.     if ($host eq "localhost") {
  490.         $ipaddr = $thisipaddr;
  491.     } else {
  492.         $ipaddr = &getipaddr($host);
  493.     }
  494.     print "  loghost $host ($ipaddr)\n" if ($opt_d);
  495.     if ($ipaddr eq "0") {
  496.         warn "${cfname}: unknown loghost $host\n";
  497.     }
  498.     }
  499. }
  500.  
  501. # no verification performed on inst commands
  502.  
  503. sub cfkey_inst {
  504.     local($cmd) = @_;
  505.  
  506.     print "${cfname}: inst $cmd\n" if ($opt_d);
  507. }
  508.  
  509. sub script_check {
  510.     local($script,$cmd) = @_;
  511.  
  512.     if (! defined $mrscripts{$script}) {
  513.     if (-e "mr$script") {
  514.         warn "${cfname}: $script command overrides mr$script, mr$script script will not be run\n";
  515.     }
  516.     $mrscripts{$script} = 1;
  517.     }
  518. }
  519.  
  520. sub cfkey_fx {
  521.     local($cmd) = @_;
  522.     local($script) = "fx";
  523.  
  524.     &script_check($script,$cmd);
  525.     print FX $cmd,"\n";        # I don't like this, but it works
  526. }
  527.  
  528. sub cfkey_init {
  529.     local($cmd) = @_;
  530.     local($script) = "init";
  531.  
  532.     &script_check($script,$cmd);
  533.     print INIT $cmd,"\n";
  534. }
  535.  
  536. sub cfkey_mkfs {
  537.     local($cmd) = @_;
  538.     local($script) = "mkfs";
  539.  
  540.     &script_check($script,$cmd);
  541.     print MKFS $cmd,"\n";
  542. }
  543.  
  544. sub cfkey_preinst {
  545.     local($cmd) = @_;
  546.     local($script) = "preinst";
  547.  
  548.     &script_check($script,$cmd);
  549.     print PREINST $cmd,"\n";
  550. }
  551.  
  552. sub cfkey_postinst {
  553.     local($cmd) = @_;
  554.     local($script) = "postinst";
  555.  
  556.     &script_check($script,$cmd);
  557.     print POSTINST $cmd,"\n";
  558. }
  559.  
  560. # getipaddr - get the IP address for a given host ($1)
  561. # returns the IP address in IPADDR global variable
  562. # returns 1 if got a name
  563.  
  564. sub getipaddr {
  565.     local($hostname) = @_;
  566.  
  567.     if (! -x $GETHOSTBYNAME) {
  568.     print "${O}: $GETHOSTBYNAME not installed, unable to lookup hostname\n";
  569.     return "0";
  570.     }
  571.  
  572.     local($addr) = `$GETHOSTBYNAME $hostname | \
  573.     nawk -v a=0 '/^$hostname / { a=\$3; exit }
  574.         END      { print a }'`;
  575.     chop $addr;
  576.     return $addr;
  577. }
  578.